using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace Beauty.Net.Middleware.Core;

/// <summary>
/// 响应包装中间件
/// </summary>
public class ResponseWrapperMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ResponseWrapperMiddleware> _logger;
    private readonly JsonSerializerOptions _jsonOptions;
    
    /// <summary>
    /// 构造函数
    /// </summary>
    public ResponseWrapperMiddleware(
        RequestDelegate next,
        ILogger<ResponseWrapperMiddleware> logger)
    {
        _next = next;
        _logger = logger;
        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = false
        };
    }
    
    /// <summary>
    /// 执行中间件逻辑
    /// </summary>
    public async Task InvokeAsync(HttpContext context)
    {
        // 不处理特殊路径（如健康检查、静态文件等）
        var path = context.Request.Path.Value;
        if (path?.StartsWith("/swagger") == true || 
            path?.StartsWith("/health") == true ||
            path?.StartsWith("/metrics") == true ||
            context.Request.ContentType?.Contains("multipart/form-data") == true)
        {
            await _next(context);
            return;
        }
        
        // 保存原始响应流
        var originalResponseBody = context.Response.Body;
        
        try
        {
            // 创建新的响应流用于捕获响应内容
            using var responseBody = new MemoryStream();
            context.Response.Body = responseBody;
            
            // 执行后续中间件
            await _next(context);
            
            // 重置响应流位置
            responseBody.Seek(0, SeekOrigin.Begin);
            
            // 读取原始响应内容
            string responseContent;
            using (var reader = new StreamReader(responseBody, leaveOpen: true))
            {
                responseContent = await reader.ReadToEndAsync();
            }
            
            // 重置响应流位置（再次使用）
            responseBody.Seek(0, SeekOrigin.Begin);
            
            // 如果是错误响应
            if (!context.Response.StatusCode.ToString().StartsWith("2"))
            {
                await HandleErrorResponse(context, context.Response.StatusCode, responseContent, originalResponseBody);
            }
            else
            {
                await HandleSuccessResponse(context, responseContent, originalResponseBody);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "响应包装中间件发生异常");
            await HandleExceptionResponse(context, ex, originalResponseBody);
        }
        finally
        {
            // 恢复原始响应流
            context.Response.Body = originalResponseBody;
        }
    }
    
    /// <summary>
    /// 处理成功响应
    /// </summary>
    private async Task HandleSuccessResponse(
        HttpContext context,
        string responseContent,
        Stream originalResponseBody)
    {
        object? data = null;
        
        // 尝试解析JSON响应内容
        if (!string.IsNullOrEmpty(responseContent))
        {
            try
            {
                data = JsonSerializer.Deserialize<object>(responseContent, _jsonOptions);
            }
            catch (JsonException)
            {
                // 如果不是有效的JSON，则直接使用原始内容
                data = responseContent;
            }
        }
        
        // 创建包装后的响应
        var wrappedResponse = ApiResponse.SuccessResponse(data);
        
        // 设置响应头和内容
        context.Response.ContentType = "application/json; charset=utf-8";
        // 保留原始状态码，不再强制设置为200
        
        // 序列化并写入响应
        var jsonResponse = JsonSerializer.Serialize(wrappedResponse, _jsonOptions);
        await originalResponseBody.WriteAsync(Encoding.UTF8.GetBytes(jsonResponse));
    }
    
    /// <summary>
    /// 处理错误响应
    /// </summary>
    private async Task HandleErrorResponse(
        HttpContext context,
        int statusCode,
        string errorContent,
        Stream originalResponseBody)
    {
        string errorMessage = GetErrorMessageByStatusCode(statusCode);
        
        // 尝试从错误内容中提取消息
        if (!string.IsNullOrEmpty(errorContent))
        {
            try
            {
                var errorObj = JsonSerializer.Deserialize<Dictionary<string, object>>(errorContent);
                if (errorObj != null)
                {
                    if (errorObj.TryGetValue("message", out var msg))
                    {
                        errorMessage = msg.ToString() ?? errorMessage;
                    }
                    else if (errorObj.TryGetValue("error", out var err))
                    {
                        errorMessage = err.ToString() ?? errorMessage;
                    }
                }
            }
            catch {}
        }
        
        // 创建错误响应
        var wrappedResponse = ApiResponse.ErrorResponse(statusCode, errorMessage);
        
        // 设置响应头和内容
        context.Response.ContentType = "application/json; charset=utf-8";
        
        // 序列化并写入响应
        var jsonResponse = JsonSerializer.Serialize(wrappedResponse, _jsonOptions);
        await originalResponseBody.WriteAsync(Encoding.UTF8.GetBytes(jsonResponse));
    }
    
    /// <summary>
    /// 处理异常响应
    /// </summary>
    private async Task HandleExceptionResponse(
        HttpContext context,
        Exception ex,
        Stream originalResponseBody)
    {
        var wrappedResponse = ApiResponse.ErrorResponse(
            500,
            "服务器内部错误: " + ex.Message);
        
        // 设置响应头和内容
        context.Response.ContentType = "application/json; charset=utf-8";
        context.Response.StatusCode = 500;
        
        // 序列化并写入响应
        var jsonResponse = JsonSerializer.Serialize(wrappedResponse, _jsonOptions);
        await originalResponseBody.WriteAsync(Encoding.UTF8.GetBytes(jsonResponse));
    }
    
    /// <summary>
    /// 根据状态码获取错误消息
    /// </summary>
    private string GetErrorMessageByStatusCode(int statusCode)
    {
        return statusCode switch
        {
            400 => "请求参数错误",
            401 => "未授权访问",
            403 => "禁止访问",
            404 => "请求的资源不存在",
            405 => "不支持的请求方法",
            500 => "服务器内部错误",
            502 => "网关错误",
            503 => "服务不可用",
            504 => "网关超时",
            _ => "请求处理失败"
        };
    }
}